/**
 * 
 */
package rs.fon.rapidminer.operator.learner.tree;

import rs.fon.rapidminer.process.annotation.Parameter;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.operator.OperatorException;
import com.rapidminer.operator.learner.tree.DecisionTreeLeafCreator;
import rs.fon.rapidminer.operator.learner.tree.FrequencyCalculator;
import com.rapidminer.operator.learner.tree.LeafCreator;
import com.rapidminer.operator.learner.tree.Terminator;
import com.rapidminer.operator.learner.tree.Tree;
import rs.fon.rapidminer.operator.learner.tree.SplittedExampleSet;
import java.util.LinkedList;
import com.rapidminer.example.Attribute;
import java.util.List;

/**
 * @author Nikola
 * 
 */
public class InforamtionGainSplit extends AbstractSplit {
	

	Attribute bestAttribute;
	int bestAttributeInt;
	SplittedExampleSet bestSplitted;
	double bestBenefit = -1;
	
	
    private static double LOG_FACTOR = 1d / Math.log(2);
    
    private FrequencyCalculator calculator = new FrequencyCalculator();
	
    @Override
	public Object DoWork(List<SplittedExampleSet> sviSplitedi, List<rs.fon.rapidminer.process.Parameter> parameters)
	{	
		
		int i=0;
		
		for(SplittedExampleSet ses : sviSplitedi)
		{
			i++;
			double currentBenefit = -1;
			
			if(ses != null)
				currentBenefit = Double.parseDouble(this.GetBenefit(ses).toString());
			
			if(currentBenefit > bestBenefit)
			{
				bestBenefit = currentBenefit;
				bestSplitted = ses;
				bestAttribute = ses.getAttribute();
			}				
		}	
		
		return bestSplitted;
	}
    @Override
    public Object GetBenefit(SplittedExampleSet exampleSet) {
	        double[] totalWeights = calculator.getLabelWeights(exampleSet);
	        double totalWeight = calculator.getTotalWeight(totalWeights);
	        double totalEntropy = getEntropy(totalWeights, totalWeight);
	        double gain = 0;
	        for (int i = 0; i < exampleSet.getNumberOfSubsets(); i++) {
	            exampleSet.selectSingleSubset(i);
	            double[] partitionWeights = calculator.getLabelWeights(exampleSet);
	            double partitionWeight = calculator.getTotalWeight(partitionWeights);
	            gain += getEntropy(partitionWeights, partitionWeight) * partitionWeight / totalWeight;
	        }
	        return totalEntropy - gain;
	    }
	    
	    public double getEntropy(double[] labelWeights, double totalWeight) {
	        double entropy = 0;
	        for (int i = 0; i < labelWeights.length; i++) {
	            if (labelWeights[i] > 0) {
	                double proportion = labelWeights[i] / totalWeight;
	                entropy -= (Math.log(proportion) * LOG_FACTOR) * proportion;
	            }
	        }
	        return entropy;
	    }
	    
	@Override
	public Object GetBestAttribute(SplittedExampleSet exampleSet)
	{
		
		return bestAttribute;
	}
	
	@Override
	public Object GetBenefit()	
	{
		return bestBenefit;
	}
	
}
